<template>
  <div class="add-container">
    <!-- 面包屑导航 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>商品管理</el-breadcrumb-item>
      <el-breadcrumb-item>商品添加</el-breadcrumb-item>
    </el-breadcrumb>
    <!-- 卡片区域 -->
    <el-card>
      <!-- 提示框 -->
      <el-alert title="添加商品信息" type="info" center show-icon :closable="false"></el-alert>
      <!-- 步骤条 -->
      <el-steps :space="200" :active="activeIndex - 0" finish-status="success" align-center>
        <el-step title="基本信息"></el-step>
        <el-step title="商品参数"></el-step>
        <el-step title="商品属性"></el-step>
        <el-step title="商品图片"></el-step>
        <el-step title="商品内容"></el-step>
        <el-step title="完成"></el-step>
      </el-steps>
      <!-- 表单区域，将侧边导航栏包裹在验证表单之内 -->
      <el-form :model="addGoodsForm" :rules="addGoodsFormRules"
        ref="addGoodsFormRef" label-width="100px" label-position="top">
        <!-- tab标签栏 -->
        <!-- 标签栏双向绑定的变量用来确定当前选中项，是一个字符串变量，
          data中初始化的数值型变量activeIndex会转换为字符串以供标签栏使用，
          但步骤条中active属性需要数值型的变量来控制当前选中步骤，
          所以在active绑定时对字符串类型的activeIndex执行-0操作隐式转换为数值类型
          befor-leave属性指定一个函数，用于控制tab标签栏的跳转行为，提供activeIndex和oldActiveIndex两个参数
          当函数return false时不允许跳转 -->
        <el-tabs :tab-position="'left'" v-model="activeIndex" :before-leave="beforLeaveTab">
          <el-tab-pane label="基本信息">
            <el-form-item label="商品名称" prop="goods_name" required>
              <el-input v-model="addGoodsForm.goods_name"></el-input>
            </el-form-item>
            <el-form-item label="商品价格" prop="goods_price" required>
              <el-input v-model="addGoodsForm.goods_price" type="number" class="no-updown"></el-input>
            </el-form-item>
            <el-form-item label="商品数量" prop="goods_number" required>
              <el-input v-model="addGoodsForm.goods_number" type="number"></el-input>
            </el-form-item>
            <el-form-item label="商品重量" prop="goods_weight" required>
              <el-input v-model="addGoodsForm.goods_weight" type="number"></el-input>
            </el-form-item>
            <el-form-item label="商品分类" prop="goods_cat">
              <!-- 级联选择器 -->
              <!-- option属性用于指定级联选择器数据源，
                v-model属性绑定的变量值为当前选中项的value值，
                该value值由props属性中value属性给定的变量决定
                v-model绑定的变量并不是addGoodsForm中的goods_cat,这样做的理由如下：
                  1、级联选择器要求选中分类的路径信息为一个数组
                  2、添加商品的api中要求商品分类为一个逗号分隔的字符串
                  3、直接将级联选择器的路径信息绑定在addGoodsForm中的goods_cat中
                    的话，在执行添加商品的请求前会将goods_cat转为字符串
                    这时级联选择器没有接收到正确类型(array)的数据，就会报错
                  4、或前期照常绑定表单对象中的goods_cat，进行数据处理时对addGoodsForm表单进行
                    深拷贝，对拷贝后的新表单对象进行操作，并作为请求参数发送给后端 -->
              <el-cascader
              v-model="currentCate"
              :options="cateList"
              :props="cateCascaderProp"
              clearable
              @change="cascaderChange"></el-cascader>
            </el-form-item>
          </el-tab-pane>
          <el-tab-pane label="商品参数">
            <!-- 渲染动态参数 -->
            <el-form-item v-for="item in manyList" :key="item.attr_id" :label="item.attr_name">
              <!-- 动态动态参数多选框组 -->
              <el-checkbox-group v-model="item.currentChecked">
                <el-checkbox v-for="(val, i) in item.attr_vals" :key="i" :label="val" border @change="manyChanged(item)"></el-checkbox>
              </el-checkbox-group>
            </el-form-item>
          </el-tab-pane>
          <el-tab-pane label="商品属性">
            <!-- 渲染静态属性表单 -->
            <el-form-item v-for="o in onlyList" :key="o.attr_id" :label="o.attr_name">
              <el-input v-model="o.attr_vals" @change="onlyChanged(o)"></el-input>
            </el-form-item>
          </el-tab-pane>
          <el-tab-pane label="商品图片">
            <!-- 上传图片组件 -->
            <!-- action：指定上传接口地址
              on-preview：预览动作的处理函数
              on-remove：移除动作的处理函数
              file-list：上传的文件列表, 例如: [{name: 'food.jpg', url: 'https://xxx.cdn.com/xxx.jpg'}]
              list-type：指定上传队列的样式 -->
            <el-upload
              :action="uploadURL"
              :headers="uploadHeaders"
              :on-preview="uploadPreview"
              :on-remove="uploadRemove"
              :file-list="fileList"
              :on-success="uploadSuccess"
              list-type="picture">
              <el-button size="small" type="primary">点击上传</el-button>
            </el-upload>
            <!-- 图片预览对话框 -->
            <el-dialog
              title="图片预览"
              :visible.sync="imgPreVisible"
              width="50%">
              <img :src="imageUrl" class="prevImg">
            </el-dialog>
          </el-tab-pane>
          <el-tab-pane label="商品内容">
            <!-- vue-quill-editor富文本编辑器组件 -->
            <!-- 富文本编辑器会将用户在文本框中输入的内容以html字符串形式存储在绑定变量中 -->
            <quill-editor v-model="addGoodsForm.goods_introduce"></quill-editor>
            <el-button type="primary" @click="addButtonClicked">添加商品</el-button>
          </el-tab-pane>
        </el-tabs>
      </el-form>
    </el-card>
  </div>
</template>

<script>
import { getCateList } from '@/api/getCateListApi.js'
import { getCateAttri } from '@/api/getCateAttriApi.js'
import { addGoods } from '@/api/goodsApi.js'
// lodash插件，本组件中用于进行深拷贝( _.cloneDeep(value) )
// import _ from 'lodash'
export default {
  name: 'myAdd',
  data () {
    return {
      // 当前选中步骤的控制变量
      activeIndex: 0,
      // 添加商品表单数据
      addGoodsForm: {
        goods_name: '',
        goods_price: 0,
        goods_number: 0,
        goods_weight: 0,
        // 商品所属分类
        goods_cat: '',
        // 商品图片路径对象的数组
        /**
         * "pics":[
         *  {"pic":"/tmp_uploads/30f08d52c551ecb447277eae232304b8"}
         * ],
         */
        pics: [],
        // 富文本编辑器内容存储变量
        goods_introduce: '',
        // 静态参数、动态属性数组
        attrs: []
      },
      // 添加商品表单校验规则
      addGoodsFormRules: {
        goods_name: []
      },
      // 分类列表
      cateList: [],
      // 级联选择器prop对象
      /**
       * expandTrigger: 触发形式，click或hover
       * value: 选中项的值，即决定选中的数据对象的哪一属性作为该数据对象的值，当被选中时，这个值以及这个数据项的父节点的同属性值会组成一个数组，传给级联选择器的v-model属性
       * label: 选中项的名字（标题），即决定选中的数据对象中的哪一属性展示在级联选择器中
       * children: 识别字节点的属性，例如属性值是'a'，那么就以a作为子节点的判断条件，该数据对象中的a属性将作为该数据对象的子节点
       */
      cateCascaderProp: {
        expandTrigger: 'hover',
        value: 'cat_id',
        label: 'cat_name',
        children: 'children'
      },
      // 级联选择器选中项绑定变量
      currentCate: [],
      // 动态参数列表
      manyList: [],
      // 静态属性列表
      onlyList: [],
      // 当前选中的动态参数数组
      currentMany: [],
      // 上传api地址
      uploadURL: 'http://127.0.0.1:8888/api/private/v1/upload',
      // 上传文件信息列表
      fileList: [],
      // 上传组件请求头对象
      uploadHeaders: {
        Authorization: window.sessionStorage.getItem('token')
      },
      // 预览对话框中图片的路径
      imageUrl: '',
      // 图片预览对话框显隐控件
      imgPreVisible: false
    }
  },
  methods: {
    // 获取所有分类
    async initCatList () {
      const { data: res } = await getCateList()
      if (res.meta.status !== 200) {
        return this.$notify.error({ title: '请求分类失败', message: res.meta.msg })
      }
      // 否则请求成功，将总分类数据存入vue的分类列表中
      this.cateList = res.data
    },
    // 获取静态或动态参数
    async getCatAttributes (om) {
      const { data: res } = await getCateAttri(this.currentCate[2], om)
      if (res.meta.status !== 200) {
        return this.$notify.error({ title: '获取属性列表失败', message: res.meta.msg })
      }
      // 否则获取成功，首先将参数、属性字符串切分为列表
      if (om === 'many') {
        res.data.forEach(item => {
          item.attr_vals = item.attr_vals.split(' ')
          // 清除空参数
          if (item.attr_vals.indexOf('') >= 0) {
            item.attr_vals = []
          }
          // 添加复选框选中数组变量
          item.currentChecked = []
        })
        // 其次将only或many添加到请求数据中
        res.data.omType = om
        this.manyList = res.data
        console.log(this.manyList)
      } else {
        this.onlyList = res.data
        console.log(this.onlyList)
      }
    },
    // 添加商品的post请求
    async postNewGoods () {
      const { data: res } = await addGoods(this.addGoodsForm)
      if (res.meta.status !== 201) {
        return this.$notify.error({ title: '添加失败', message: res.meta.msg })
      }
      // 否则请求成功
      this.$notify.success({ title: '添加成功' })
    },
    // 级联选择器值变化
    cascaderChange () {
      // 添加判断条件，禁止选择除三级分类以外的分类
      if (this.currentCate.length !== 3) {
        this.currentCate = []
        return this.$notify.error({ title: '请选择三级分类' })
      }
      // 否则选中了三级分类，
      // 将分类数组转字符串赋值给表单对象的goodsCate属性
      this.addGoodsForm.goods_cat = this.currentCate.join(',')
      console.log('当前选中分类', this.addGoodsForm)
    },
    // tab标签栏跳转前的事件
    beforLeaveTab (toName, fromName) {
      // console.log(acitveName, oldACtiveName)
      // 添加判断条件，未选中三级分类时不允许跳转tab标签
      if (fromName === '0' && this.currentCate.length !== 3) {
        this.$notify.error({ title: '请先选择商品分类' })
        return false
      } else if (toName === '1') {
        // 跳转至动态参数栏，请求动态参数
        this.getCatAttributes('many')
      } else if (toName === '2') {
        // 跳转至静态属性栏，请求静态属性
        this.getCatAttributes('only')
      }
    },
    // 动态参数复选框变化事件
    manyChanged (cArray) {
      // 已经将选中的参数添加到manyList的当前参数的currentChecked数组中
      // 在提交表单前之前只需要将currentchecked数组join为字符串提交即可
      console.log(this.manyList)
    },
    // 静态属性输入框变化事件
    onlyChanged (cArray) {
      console.log(this.onlyList)
    },
    // 上传组件预览事件的处理函数
    uploadPreview (file) {
      // 将图片路径赋给imageUrl
      this.imageUrl = file.response.data.url
      // 显示图片预览对话框
      this.imgPreVisible = true
    },
    // 上传组件移除事件的处理函数
    uploadRemove (file, fileList) {
      // 根据file中respoinse-->data-->tmp_path找到删除的图片路径
      // 在表单对象addGoodsForm的pics数组的每一个图片信息对象中查找tmp_path，获得删除图片的索引
      // 调用splice方法删除pics数组中的对应图片信息对象
      const i = this.addGoodsForm.pics.findIndex(item => item.pic === file.response.data.tmp_path)
      this.addGoodsForm.pics.splice(i, 1)
    },
    // 上传组件成功事件的处理函数
    uploadSuccess (res, file, fileList) {
      if (res.meta.status !== 200) {
        return this.$notify.error({ title: res.meta.msg })
      }
      this.addGoodsForm.pics.push({ pic: res.data.tmp_path })
      // console.log(this.addGoodsForm)
    },
    // 添加商品按钮点击事件处理
    addButtonClicked () {
      this.$refs.addGoodsFormRef.validate(cb => {
        // 若表单验证失败
        if (!cb) {
          return this.$notify.error({ title: '请填写必要表单项' })
        }
        // 否则发起添加商品请求

        /**
         * 若级联选择器没有单独绑定路径信息，则需要进行深拷贝
         * 通过第三方插件lodash实现
         * 以下代码假设没有给级联选择器单独绑定路径信息，是不必要的代码
         */
        // // 深拷贝表单对象
        // const subForm = _.cloneDeep(this.addGoodsForm)
        // // 切分为数组模拟级联选择器直接绑定表单中的分类属性的情况
        // subForm.goods_cat = subForm.goods_cat.split(',')
        // // 进行join，形成字符串
        // subForm.goods_cat = subForm.goods_cat.join(',')
        // console.log(subForm)

        // 处理动态参数,拼接回空格分割的字符串
        this.manyList.forEach(manyItem => {
          // 当前item中存在currentChecked数组用于存放选中的动态参数
          // 只需要将currentChecked数组join后push到addGoodsForm的attrs属性中即可
          this.addGoodsForm.attrs.push({
            attr_id: manyItem.attr_id,
            attr_vals: manyItem.currentChecked.join(' ')
          })
        })
        // 处理静态属性,直接添加到表单的attrs数组中
        this.onlyList.forEach(onlyItem => {
          // 由于静态属性没有进行split，用户在修改时直接操作arrt_vals
          // 故直接将attr_vals值赋给匿名对象并将对象push至attrs数组即可
          this.addGoodsForm.attrs.push({
            attr_id: onlyItem.attr_id,
            attr_vals: onlyItem.attr_vals
          })
        })
        // console.log(this.addGoodsForm)
        // 处理完成后发送请求
        this.postNewGoods()
      })
    }
  },
  created () {
    this.initCatList()
  },
  computed: {
  }
}
</script>

<style lang="less" scoped>
.el-steps {
  margin: 20px 0;
}
// /deep/.no-updown input::-webkit-outer-spin-button,
// input::-webkit-inner-spin-button {
//     -webkit-appearance: none;
// }
// /deep/.no-updown input[type="number"]{
//     -moz-appearance: textfield;
// }
.el-checkbox {
  margin: 0 10px;
}
// 预览图片
.prevImg {
  width: 100%;
}
// 添加商品按钮
.el-button {
  margin-top: 20px;
}
</style>
